package com.ryskoo.catering.ordermain.service;

import com.alibaba.fastjson.JSON;
import com.ryskoo.basicdata.area.city.domain.CityPO;
import com.ryskoo.basicdata.area.city.service.ICityService;
import com.ryskoo.basicdata.area.province.domain.ProvincePO;
import com.ryskoo.basicdata.area.province.service.IProvinceService;
import com.ryskoo.basicdata.area.region.domain.RegionPO;
import com.ryskoo.basicdata.area.region.service.IRegionService;
import com.ryskoo.basicdata.weixin.domain.WeixinParamPO;
import com.ryskoo.basicdata.weixin.service.IWeixinParamService;
import com.ryskoo.catering.consumestatistics.service.IConsumeStatisticsService;
import com.ryskoo.catering.coupondetail.service.ICouponDetailService;
import com.ryskoo.catering.orderaddress.domain.OrderAddressPO;
import com.ryskoo.catering.orderaddress.service.IOrderAddressService;
import com.ryskoo.catering.orderdetail.domain.OrderDetailPO;
import com.ryskoo.catering.orderdetail.service.IOrderDetailService;
import com.ryskoo.catering.orderlog.domain.OrderLogPO;
import com.ryskoo.catering.orderlog.service.IOrderLogService;
import com.ryskoo.catering.ordermain.domain.OrderMainPO;
import com.ryskoo.catering.ordermain.repository.IOrderMainRepository;
import com.ryskoo.catering.ordermain.repository.OrderMessage;
import com.ryskoo.catering.ordermain.repository.RedisQueue;
import com.ryskoo.catering.productattrvalue.domain.ProductAttrValuePO;
import com.ryskoo.catering.productattrvalue.service.IProductAttrValueService;
import com.ryskoo.catering.productimage.domain.ProductImagePO;
import com.ryskoo.catering.productimage.service.IProductImageService;
import com.ryskoo.catering.productmain.domain.ProductMainPO;
import com.ryskoo.catering.productmain.repository.IProductMainRepository;
import com.ryskoo.common.constant.EurekaServiceName;
import com.ryskoo.common.constant.SystemConstant;
import com.ryskoo.common.dto.customer.VendorIndexInfo;
import com.ryskoo.common.hclconstant.*;
import com.ryskoo.customer.customer.domain.CustomerPO;
import com.ryskoo.customer.customer.service.ICustomerService;
import com.ryskoo.customer.customeraccount.domain.CustomerAccountPO;
import com.ryskoo.customer.customeraccount.service.ICustomerAccountService;
import com.ryskoo.customer.customerintegral.service.ICustomerIntegralService;
import com.ryskoo.customer.vendor.domain.VendorPO;
import com.ryskoo.customer.vendor.service.IVendorService;
import com.ryskoo.customer.vendorbasic.domain.VendorBasicPO;
import com.ryskoo.customer.vendorbasic.service.IVendorBasicService;
import com.ryskoo.customer.vendordiscounts.domain.VendorDiscountsPO;
import com.ryskoo.customer.vendordiscounts.service.IVendorDiscountsService;
import com.ryskoo.customer.vendorinfo.domain.VendorInfoPO;
import com.ryskoo.customer.vendorinfo.service.IVendorInfoService;
import com.ryskoo.customer.vendormanager.domain.VendorManagerPO;
import com.ryskoo.customer.vendormanager.service.IVendorManagerService;
import com.ryskoo.framework.core.bean.BasicPO;
import com.ryskoo.framework.core.bean.QueryConditionEnum;
import com.ryskoo.framework.core.bean.QueryMessageDTO;
import com.ryskoo.framework.core.exception.InvalidParamException;
import com.ryskoo.framework.core.generator.SnowflakeIdWorker;
import com.ryskoo.framework.core.service.BasicServiceImpl;
import com.ryskoo.framework.core.utils.DateFormatHelper;
import com.ryskoo.framework.core.utils.DoubleFormatUtil;
import com.ryskoo.thirdparty.transaction.TransactionPO;
import com.ryskoo.thirdparty.transaction.service.ITransactionService;
import com.ryskoo.thirdparty.weixinpay.WeixinPay;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;

import java.math.BigDecimal;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author BeHappy
 */
@Service
public class OrderMainServiceImpl extends BasicServiceImpl<OrderMainPO> implements IOrderMainService {
    private static final Logger logger = LogManager.getLogger(EurekaServiceName.CATERING_SERVICE);

    @Autowired
    private IOrderMainRepository orderMainRepository;

    @PostConstruct
    public void init() {
        this.setDao(orderMainRepository);
    }

    @Value("${orderDetail.url}")
    private String orderDetailUrl;

    @Autowired
    private IOrderDetailService orderDetailService;
    @Autowired
    private IOrderAddressService orderAddressService;
    @Autowired
    private IOrderLogService orderLogService;

    @Autowired
    private IVendorService vendorService;
    @Autowired
    private ICustomerService customerService;
    @Autowired
    private ICustomerAccountService customerAccountService;
    @Autowired
    private IProductImageService productImageService;
    @Autowired
    private IConsumeStatisticsService consumeStatisticsService;
    @Autowired
    private ICustomerIntegralService customerIntegralService;
    @Autowired
    private IProvinceService provinceService;
    @Autowired
    private ICityService cityService;
    @Autowired
    private IRegionService regionService;
    @Autowired
    private IVendorManagerService vendorManagerService;
    @Autowired
    @Lazy
    private IProductMainRepository productMainRepository;
    @Autowired
    private IVendorDiscountsService vendorDiscountsService;
    @Autowired
    private IVendorBasicService vendorBasicService;
    @Autowired
    private IWeixinParamService weixinParamService;
    @Autowired
    private IVendorInfoService vendorInfoService;
    @Autowired
    private ICouponDetailService couponDetailService;
    @Autowired
    RedisQueue redisQueue;
    @Autowired
    private ITransactionService transactionService;
    @Autowired
    private IProductAttrValueService productAttrValueService;

    /**
     * 根据订单编号获取订单
     *
     * @param orderId
     * @return
     */
    @Override
    public OrderMainPO getByOrderId(String orderId) {
        return orderMainRepository.getByOrderId(orderId);
    }

    /**
     * 获取订单系列数据（包含订单信息、订单明细、订单收货地址、订单日志）
     * 通常在订单详情页可以调用此接口
     *
     * @param uuid
     * @return
     */
    @Override
    public OrderMainPO getFamily(String uuid, String invokeFrom) {
        OrderMainPO order = orderMainRepository.getByUuid(uuid);
        if (order != null) {
            List<OrderDetailPO> detailList = orderDetailService.getDetailListByOrderUuid(uuid);
            //后台管理需要获取订单日志
            if ("backWeb".equals(invokeFrom)) {
                List<OrderLogPO> logList = orderLogService.getLogListByOrderUuid(uuid);
                order.setLogList(logList);
            }
            //餐饮行业外卖、鲜花行业快递，需要查询订单收货地址
            if (EatTypeEnum.WAIMAI.getValue() == order.getEatType() || SendTypeEnum.EXPRESS.getValue() == order.getSendType()) {
                OrderAddressPO orderAddress = orderAddressService.getAddressByOrderUuid(uuid);
                if (null != orderAddress) {
                    ProvincePO provincePO = provinceService.getByUuid(orderAddress.getProvinceUuid());
                    CityPO cityPO = cityService.getByUuid(orderAddress.getCityUuid());
                    RegionPO regionPO = regionService.getByUuid(orderAddress.getRegionUuid());
                    orderAddress.setProvince(provincePO == null ? "" : provincePO.getName());
                    orderAddress.setCity(cityPO == null ? "" : cityPO.getName());
                    orderAddress.setRegion(regionPO == null ? "" : regionPO.getName());
                }
                order.setOrderAddress(orderAddress);
            }

            //获取所有的商品图片
            QueryMessageDTO imgQM = new QueryMessageDTO();
            imgQM.addCondition("productUuid", QueryConditionEnum.IN.name(), detailList.stream().map(OrderDetailPO::getProductUuid).collect(Collectors.toList()));
            List<ProductImagePO> imgList = productImageService.queryByCondition(imgQM);
            //将图片集合转换成map, key=productUuid, value=ProductImagePO, 参数(key1, key2) -> key2 表示去重
            Map<String, ProductImagePO> imgMap = imgList.stream().collect(Collectors.toMap(ProductImagePO::getProductUuid, Function.identity(), (key1, key2) -> key2));

            for (OrderDetailPO detailPO : detailList) {
                ProductImagePO image = imgMap.get(detailPO.getProductUuid());
                if (null != image) {
                    detailPO.setProductImg(image.getSmallImg());
                }
            }

            order.setDetailList(detailList);
        }
        return order;
    }

    /**
     * 支付
     *
     * @param payResult
     */
    @Override
    public OrderMainPO pay(Map<String, Object> payResult) {
        String orderId = MapUtils.getString(payResult, "orderNo");
        String transactionId = MapUtils.getString(payResult, "transactionId");
        int totalFee = MapUtils.getIntValue(payResult, "totalFee");
        //修改订单状态
        OrderMainPO order = this.getByOrderId(orderId);
        if (null == order) {
            throw new InvalidParamException("订单号不存在");
        }
        if (PayStateEnum.PAID.getValue() == order.getPayState()) {
            // 订单已支付，则直接返回结果 （微信支付重复通知的情况）
            return order;
        }
        if (PayStateEnum.UNPAID.getValue() != order.getPayState()) {
            throw new InvalidParamException("支付状态错误");
        }
        int price = (int) (order.getPayPrice() * 100);
        if (price != totalFee) {
            throw new InvalidParamException("支付金额错误");
        }

        order.setPayState(PayStateEnum.PAID.getValue());
        order.setPayType(PayTypeEnum.WECHATPAY.getValue());
        order.setWechatPay(MapUtils.getInteger(payResult, "wechatPay"));
        order.setPayTime(DateFormatHelper.getNowTimeStr());
        // 保存支付流水号
        order.setPayId(transactionId);

        orderMainRepository.update(order);

        //创建日志
        String operateLog = "订单支付";
        orderLogService.createLog(order.getUuid(), order.getCustomerUuid(), order.getCustomerName(), operateLog);

        if (order.getGiveIntegral() > 0) {
            //赠送积分
            customerIntegralService.addByOrder(order.getCustomerUuid(), order.getVendorUuid(), order.getEntityNo(), order.getGiveIntegral());
        }

        //创建消费统计
        consumeStatisticsService.create(order.getVendorUuid(), order.getCustomerUuid(), order.getPayPrice());
        return order;
    }

    /**
     * 收款（商户收款）
     *
     * @param orderUuid
     * @param payMoney
     * @param operatorUuid
     * @param operatorName
     */
    @Override
    public OrderMainPO gathering(String orderUuid, double payMoney, String operatorUuid, String operatorName) {
        //修改订单状态
        OrderMainPO order = orderMainRepository.getByUuid(orderUuid);
        if (EatTypeEnum.TANGSHI.getValue() == order.getEatType()) {
            order.setState(OrderStateEnum.FINISH.getValue());
            order.setFinishTime(DateFormatHelper.getNowTimeStr());

            //餐饮订单接单后，订单明细状态修改
            if (IndustryEnum.FOODS.getValue().equals(order.getIndustry())) {
                List<OrderDetailPO> detailList = orderDetailService.getDetailListByOrderUuid(orderUuid);
                if (CollectionUtils.isNotEmpty(detailList)) {
                    detailList.forEach(detail -> detail.setState(CookStateEnum.COOKED.getValue()));
                    orderDetailService.batchUpdate(detailList);
                }
                order.setDetailList(detailList);
            }
        }
        order.setPayState(PayStateEnum.PAID.getValue());
        order.setPayType(PayTypeEnum.OFFLINE.getValue());
        order.setPayTime(DateFormatHelper.getNowTimeStr());

        order.setPayPrice(payMoney);
        order.setFreePrice(DoubleFormatUtil.subtract(order.getTotalPrice(), order.getPayPrice()));
        order.setOtherPrice(DoubleFormatUtil.subtract(order.getFreePrice(), order.getMjPrice(), order.getLjPrice(), order.getIntegralFree()));
        orderMainRepository.update(order);

        //创建日志
        String operateLog = "商户收款";
        orderLogService.createLog(order.getUuid(), operatorUuid, operatorName, operateLog);

        if (order.getGiveIntegral() > 0) {
            //赠送积分
            customerIntegralService.addByOrder(order.getCustomerUuid(), order.getVendorUuid(), order.getEntityNo(), order.getGiveIntegral());
        }

        //创建消费统计
        consumeStatisticsService.create(order.getVendorUuid(), order.getCustomerUuid(), order.getPayPrice());
        return order;
    }

    /**
     * 商家取消订单
     *
     * @param orderUuid
     * @param refundMoney
     * @param operatorUuid
     * @param operatorName
     */
    @Override
    public OrderMainPO cancelFromVendor(String orderUuid, double refundMoney, String operatorUuid, String operatorName) {
        //修改订单状态
        OrderMainPO order = orderMainRepository.getByUuid(orderUuid);
        if (OrderStateEnum.CANCELED.getValue() == order.getState() ||
                OrderStateEnum.FINISH.getValue() == order.getState() ||
                OrderStateEnum.ARRIVED.getValue() == order.getState()) {
            throw new InvalidParamException("订单状态错误");
        }

        //微信支付且支付成功的订单，调用微信退款接口
        if (PayTypeEnum.WECHATPAY.getValue() == order.getPayType() &&
                PayStateEnum.PAID.getValue() == order.getPayState()) {
            if (refundMoney == 0.0) {
                throw new InvalidParamException("退款金额不能为0");
            }
            if (refundMoney > order.getPayPrice()) {
                throw new InvalidParamException("退款金额不能大于订单金额");
            }
            Map<String, Object> reqRefund = wxReqRefund(orderUuid, refundMoney, "商家取消订单");
            boolean result = reqRefund.get("success") == null ? false : (Boolean) reqRefund.get("success");
            if (result) {
                order.setRefundState(RefundStateEnum.REFUNDING.getValue());
                return cancel(order, operatorUuid, operatorName);
            } else {
                throw new InvalidParamException("申请退款失败");
            }
        }

        return cancel(order, operatorUuid, operatorName);
    }

    /**
     * 会员取消订单
     *
     * @param orderUuid
     */
    @Override
    public OrderMainPO cancelFromCustomer(String orderUuid) {
        //修改订单状态
        OrderMainPO order = orderMainRepository.getByUuid(orderUuid);
        if (PayStateEnum.UNPAID.getValue() != order.getPayState()) {
            throw new InvalidParamException("支付状态错误");
        }
        return cancel(order, order.getCustomerUuid(), order.getCustomerName());
    }

    /**
     * 取消
     *
     * @param order
     * @param operatorUuid
     * @param operatorName
     */
    @Override
    public OrderMainPO cancel(OrderMainPO order, String operatorUuid, String operatorName) {
        //修改订单状态
        order.setState(OrderStateEnum.CANCELED.getValue());
        orderMainRepository.update(order);

        // 取消订单，修改首页统计信息，将消息发送至redis队列
        // 未接单的订单，还未计入今天的收入，不必发送取消订单消息
        if (OrderStateEnum.SUBMIT.getValue() != order.getState()) {
            redisQueue.pushMessage(new OrderMessage(order.getVendorUuid(), order.getCreateTime(), order.getPayPrice(), order.getPersonNum(), 0));
        }

        //创建日志
        String operateLog = "取消订单";
        orderLogService.createLog(order.getUuid(), operatorUuid, operatorName, operateLog);

        //订单使用的积分进行退回
        if (order.getUseIntegral() > 0) {
            customerIntegralService.addByCancelOrder(order.getCustomerUuid(), order.getVendorUuid(), order.getEntityNo(), order.getUseIntegral());
        }
        return order;
    }

    /**
     * 退款成功回调
     *
     * @param orderId      订单号
     * @param refundStatus 退款状态
     * @param successTime  退款成功时间
     * @param callbackMsg  退款失败原因
     */
    @Override
    public OrderMainPO refundCallback(String orderId, String refundStatus, String successTime, String callbackMsg) {
        //修改订单状态
        OrderMainPO order = orderMainRepository.getByOrderId(orderId);

        String logNote = "";
        if ("SUCCESS".equals(refundStatus)) {
            order.setRefundState(RefundStateEnum.REFUNDED.getValue());
            order.setRefundTime(successTime);
            logNote = "微信退款成功";
        } else {
            order.setRefundState(RefundStateEnum.REFUND_ERROR.getValue());
            logNote = "微信退款失败，原因：" + callbackMsg;
        }

        this.update(order);
        orderLogService.createLog(order.getUuid(), "", "系统后台", logNote);
        return order;
    }

    /**
     * 商家接单
     *
     * @param orderUuid
     * @param operatorUuid
     * @param operatorName
     */
    @Override
    public OrderMainPO receive(String orderUuid, String operatorUuid, String operatorName) {
        //修改订单状态
        OrderMainPO order = orderMainRepository.getByUuid(orderUuid);
        if (OrderStateEnum.SUBMIT.getValue() != order.getState()) {
            throw new InvalidParamException("订单状态错误");
        }
        order.setState(OrderStateEnum.VENDOR_RECEIVE.getValue());
        order.setReceiveTime(DateFormatHelper.getNowTimeStr());
        //设置服务员uuid
        order.setWaiterUuid(operatorUuid);
        orderMainRepository.update(order);

        //餐饮订单接单后，订单明细状态修改，仅限堂食
        if (IndustryEnum.FOODS.getValue().equals(order.getIndustry()) && EatTypeEnum.TANGSHI.getValue() == order.getEatType()) {
            List<OrderDetailPO> detailList = orderDetailService.getDetailListByOrderUuid(orderUuid);
            if (CollectionUtils.isNotEmpty(detailList)) {
                detailList.forEach(detail -> detail.setState(CookStateEnum.COOKING.getValue()));
                orderDetailService.batchUpdate(detailList);
            }
            order.setDetailList(detailList);
        }
        // 商家接单，修改首页统计数据，将消息发送给redis队列
        redisQueue.pushMessage(new OrderMessage(order.getVendorUuid(), order.getCreateTime(), order.getPayPrice(), order.getPersonNum(), 1));

        //创建日志
        String operateLog = "商家接单";
        orderLogService.createLog(order.getUuid(), operatorUuid, operatorName, operateLog);
        return order;
    }

    /**
     * 商家完成订单
     *
     * @param orderUuid
     * @param operatorUuid
     * @param operatorName
     */
    @Override
    public OrderMainPO finish(String orderUuid, String operatorUuid, String operatorName) {
        //修改订单状态
        OrderMainPO order = orderMainRepository.getByUuid(orderUuid);
        if (OrderStateEnum.VENDOR_RECEIVE.getValue() != order.getState()) {
            throw new InvalidParamException("订单状态错误");
        }
        if (PayStateEnum.PAID.getValue() != order.getPayState()) {
            throw new InvalidParamException("支付状态错误");
        }
        order.setState(OrderStateEnum.FINISH.getValue());
        order.setFinishTime(DateFormatHelper.getNowTimeStr());
        orderMainRepository.update(order);

        //餐饮订单接单后，订单明细状态修改，仅限堂食
        if (IndustryEnum.FOODS.getValue().equals(order.getIndustry()) && EatTypeEnum.TANGSHI.getValue() == order.getEatType()) {
            List<OrderDetailPO> detailList = orderDetailService.getDetailListByOrderUuid(orderUuid);
            if (CollectionUtils.isNotEmpty(detailList)) {
                detailList.forEach(detail -> detail.setState(CookStateEnum.COOKED.getValue()));
                orderDetailService.batchUpdate(detailList);
            }
            order.setDetailList(detailList);
        }

        //创建日志
        String operateLog = "商家完成订单";
        orderLogService.createLog(order.getUuid(), operatorUuid, operatorName, operateLog);
        return order;
    }

    /**
     * 订单派送
     *
     * @param orderUuid
     * @param operatorUuid
     * @param operatorName
     */
    @Override
    public OrderMainPO delivery(String orderUuid, String operatorUuid, String operatorName) {
        //修改订单状态
        OrderMainPO order = orderMainRepository.getByUuid(orderUuid);
        if (OrderStateEnum.VENDOR_RECEIVE.getValue() != order.getState()) {
            throw new InvalidParamException("订单状态错误");
        }
        order.setState(OrderStateEnum.DELIVERY.getValue());
        order.setDeliveryTime(DateFormatHelper.getNowTimeStr());
        orderMainRepository.update(order);

        //创建日志
        String operateLog = "订单派送";
        orderLogService.createLog(order.getUuid(), operatorUuid, operatorName, operateLog);
        return order;
    }

    /**
     * 订单已送达
     *
     * @param orderUuid
     * @param operatorUuid
     * @param operatorName
     */
    @Override
    public OrderMainPO arrived(String orderUuid, String operatorUuid, String operatorName) {
        //修改订单状态
        OrderMainPO order = orderMainRepository.getByUuid(orderUuid);
        if (OrderStateEnum.DELIVERY.getValue() != order.getState()) {
            throw new InvalidParamException("订单状态错误");
        }
        order.setState(OrderStateEnum.ARRIVED.getValue());
        order.setFinishTime(DateFormatHelper.getNowTimeStr());
        orderMainRepository.update(order);

        //创建日志
        String operateLog = "订单已送达";
        orderLogService.createLog(order.getUuid(), operatorUuid, operatorName, operateLog);
        return order;
    }

    /**
     * 订单修改价格
     *
     * @param orderUuid
     * @param price
     * @param operatorUuid
     * @param operatorName
     */
    @Override
    public OrderMainPO editPrice(String orderUuid, double price, String operatorUuid, String operatorName) {
        OrderMainPO order = orderMainRepository.getByUuid(orderUuid);
        if (PayStateEnum.PAID.getValue() == order.getPayState()) {
            throw new InvalidParamException("订单已支付，不能修改价格");
        }
        if (price > order.getPayPrice()) {
            throw new InvalidParamException("修改后的价格大于订单应付金额");
        }
        StringBuilder operateLog = new StringBuilder();
        operateLog.append("订单改价【订单修改前价格：").append(order.getPayPrice());
        order.setPayPrice(price);
        order.setFreePrice(DoubleFormatUtil.subtract(order.getTotalPrice(), order.getPayPrice()));
        order.setOtherPrice(DoubleFormatUtil.subtract(order.getFreePrice(), order.getMjPrice(), order.getLjPrice(), order.getIntegralFree()));
        orderMainRepository.update(order);

        operateLog.append("，订单修改后价格：").append(order.getPayPrice()).append("】");
        //创建日志
        orderLogService.createLog(order.getUuid(), operatorUuid, operatorName, operateLog.toString());
        return order;
    }

    /**
     * 服务员代客下单
     *
     * @param po
     * @return
     */
    @Override
    public String saveForWaiter(OrderMainPO po) {
        logger.info("【代客下单】输入订单信息：" + JSON.toJSONString(po));
        genOrder(po);
        genOrderDiscount(po);
        /* 订单校验 */
        validata(po);
        /* 订单主信息保存 */
        String orderUuid = saveOrderMain(po);
        /* 订单明细保存 */
        orderDetailService.saveOrderDetail(po);
        /* 订单日志保存 */
        orderLogService.createLog(orderUuid, po.getCustomerUuid(), po.getCustomerName(), "代客下单");
        /* 由于是服务员代客下单，没有会员信息，因此也没有优惠券等，也不会用积分抵扣 */
        logger.info("输出订单信息：" + JSON.toJSONString(po));
        return orderUuid;
    }

    /**
     * 订单保存
     *
     * @param po
     * @return 订单uuid
     */
    @Override
    public String save(OrderMainPO po) {
        logger.info("输入订单信息：" + JSON.toJSONString(po));
        /*订单校验*/
        validata(po);
        /*订单信息保存*/
        String orderUuid = saveOrderMain(po);
        /*订单明细保存*/
        orderDetailService.saveOrderDetail(po);

        /*保存订单收货地址*/
        if (!StringUtils.isEmpty(po.getAddressUuid())) {
            orderAddressService.createAddress(po.getUuid(), po.getAddressUuid());
        }
        /*订单日志保存*/
        orderLogService.createLog(orderUuid, po.getCustomerUuid(), po.getCustomerName(), "下单");

        /*使用店铺优惠券*/
        if (StringUtils.isNotEmpty(po.getCouponDetailUuid())) {
            couponDetailService.used(po.getCouponDetailUuid(), po.getEntityNo());
        }
        List<OrderDetailPO> detailList = po.getDetailList();
        if (null != detailList) {
            //获取所有的单品类优惠券明细uuid集合,并过滤非空
            List<String> couponDetailUuids = detailList.stream().map(OrderDetailPO::getCouponDetailUuid).filter(x -> StringUtils.isNotEmpty(x)).collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(couponDetailUuids)) {
                /*使用优惠券*/
                couponDetailService.used(couponDetailUuids, po.getEntityNo());
            }
        }

        /*下单使用积分*/
        if (po.getUseIntegral() > 0) {
            customerIntegralService.useByOrder(po.getCustomerUuid(), po.getVendorUuid(), po.getEntityNo(), po.getUseIntegral());
        }

        logger.info("输出订单信息：" + JSON.toJSONString(po));
        return orderUuid;
    }

    private String saveOrderMain(OrderMainPO po) {
        VendorPO vendor = vendorService.getByUuid(po.getVendorUuid());
        if (null == vendor) {
            throw new InvalidParamException("商户为空");
        }
        // 如果是服务员代客人下单，就没有会员，所以不做判断
        if (StringUtils.isEmpty(po.getWaiterUuid())) {
            CustomerPO customer = customerService.getByUuid(po.getCustomerUuid());
            if (null == customer) {
                throw new InvalidParamException("会员为空");
            }
            po.setCustomerName(customer.getLoginName());
            CustomerAccountPO customerAccount = customerAccountService.getByCustomerUuid(po.getCustomerUuid());
            if (null == customerAccount) {
                throw new InvalidParamException("会员为空");
            }
            String birthday = customerAccount.getBirthday();
            if (StringUtils.isNotEmpty(birthday)) {
                String nowTime = DateFormatHelper.getNowTimeStr(DateFormatHelper.FORMAT_DATE_STR);
                //如果是生日当天下单，则订单记录生日日期
                if (nowTime.substring(5).equals(birthday.substring(5))) {
                    po.setBirthday(nowTime);
                }
            }
        }

        //餐饮行业需要判断是否打烊
        if (IndustryEnum.FOODS.getValue().equals(vendor.getIndustryCate())) {
            VendorInfoPO vendorInfoPO = vendorInfoService.getByVendorUuid(po.getVendorUuid());
            if (!vendorInfoPO.isOpen()) {
                throw new InvalidParamException("店铺已打烊，明天请赶早");
            }
        }

        po.setIndustry(vendor.getIndustryCate());
        po.setVendorName(vendor.getVendorName());

        //设置订单号
        po.setEntityNo(new SnowflakeIdWorker().nextId() + "");
        //设置订单状态
        po.setState(OrderStateEnum.SUBMIT.getValue());
        //设置支付状态
        po.setPayState(PayStateEnum.UNPAID.getValue());

        this.create(po);

        return po.getUuid();
    }

    private void validata(OrderMainPO po) {
        // 如果是服务员代客人下单，则不校验会员
        if (StringUtils.isEmpty(po.getWaiterUuid())) {
            if (StringUtils.isEmpty(po.getCustomerUuid())) {
                throw new InvalidParamException("会员uuid为空");
            }
        }
        if (StringUtils.isEmpty(po.getVendorUuid())) {
            throw new InvalidParamException("商户uuid为空");
        }
        //总金额校验
        if (po.getTotalPrice() != DoubleFormatUtil.add(po.getProductPrice(), po.getDeliveryPrice(), po.getTablewarePrice())) {
            throw new InvalidParamException("订单总金额不匹配");
        }
        //支付金额校验
        if (po.getPayPrice() != DoubleFormatUtil.subtract(po.getTotalPrice(), po.getFreePrice())) {
            throw new InvalidParamException("订单应付金额不匹配");
        }
        //优惠金额校验
        if (po.getFreePrice() != DoubleFormatUtil.add(po.getMjPrice(), po.getLjPrice(), po.getProductCouponFreePrice(), po.getVendorCouponFreePrice(), po.getIntegralFree(), po.getOtherPrice())) {
            throw new InvalidParamException("订单优惠金额不匹配");
        }
    }

    @Override
    public int getOrderCountByDate(String date, String vendorUuid) {
        return orderMainRepository.getOrderCountByDate(date, vendorUuid);
    }

    @Override
    public double getOrderAmtByDate(String date, String vendorUuid) {
        return orderMainRepository.getOrderAmtByDate(date, vendorUuid);
    }

    /**
     * 查询过去n天的商户每日统计信息
     * 收入、订单数、就餐人数
     * 如果时间为空，则查询所有的数据
     *
     * @param vendorUuid 商户uuid
     * @param days       天数
     * @return
     */
    @Override
    public List<VendorIndexInfo> getDailyIndexInfoLastDays(String vendorUuid, int days) {
        List<VendorIndexInfo> infoList = new ArrayList<>();
        if (SystemConstant.CONSTANT_ZERO == days) {
            VendorIndexInfo info = orderMainRepository.getDailyVendorIndexInfo(vendorUuid, null);
            info.setIncome(null != info.getIncome() ? info.getIncome() : 0.0);
            infoList.add(info);
        } else {
        	  for (int i = 1; i <= days; i++) {
                  String date = DateFormatHelper.getTimeStr(DateFormatHelper.FORMAT_DATE_STR, DateFormatHelper.getDateBefore(new Date(), i));
                  VendorIndexInfo info = orderMainRepository.getDailyVendorIndexInfo(vendorUuid, date);
                  info.setDate(date);
                  info.setIncome(null != info.getIncome() ? info.getIncome() : 0.0);
                  infoList.add(info);
              }
        }
      
        Collections.reverse(infoList);
        return infoList;
    }

    /**
     * 查询商品月销数量
     *
     * @param products
     * @return
     */
    @Override
    public Map<String, Integer> getMonthSellNum(List<String> products) {
        //获取近一个月的时间区间。
        //今天0点
        Date todayDate = DateFormatHelper.toDate(DateFormatHelper.getNowTimeStr(DateFormatHelper.FORMAT_DATE_STR));
        //30天前0点
        Date monthBeforeDate = DateFormatHelper.getDateBefore(todayDate, 30);
        String todayDateStr = DateFormatHelper.getTimeStr(todayDate);
        String monthBeforeDateStr = DateFormatHelper.getTimeStr(monthBeforeDate);

        Map<String, Integer> map = new HashMap<>();
        List<Object[]> list = orderMainRepository.getMonthSellNum(products, todayDateStr, monthBeforeDateStr);
        if (CollectionUtils.isNotEmpty(list)) {
            for (Object[] obj : list) {
                if (obj != null) {
                    String productUuid = obj[0] == null ? "" : (String) obj[0];
                    int buyNum = obj[1] == null ? 0 : ((BigDecimal) obj[1]).intValue();
                    map.put(productUuid, buyNum);
                }
            }
        }
        return map;
    }

    /**
     * 查询1个月内商户月销商品数量
     *
     * @param vendorUuid
     * @return
     */
    @Override
    public int getMonthSellProductNum(String vendorUuid) {
        //获取近一个月的时间区间。
        //今天0点
        Date todayDate = DateFormatHelper.toDate(DateFormatHelper.getNowTimeStr(DateFormatHelper.FORMAT_DATE_STR));
        //30天前0点
        Date monthBeforeDate = DateFormatHelper.getDateBefore(todayDate, 30);
        String todayDateStr = DateFormatHelper.getTimeStr(todayDate);
        String monthBeforeDateStr = DateFormatHelper.getTimeStr(monthBeforeDate);
        return orderMainRepository.getMonthSellProductNum(vendorUuid, todayDateStr, monthBeforeDateStr);
    }

    /**
     * 前台查询订单列表
     *
     * @param qm
     * @return
     */
    @Override
    public List<OrderMainPO> getList4FrontAndPage(QueryMessageDTO qm) {
        List<OrderMainPO> list = this.queryByConditionAndPage(qm);
        if (CollectionUtils.isEmpty(list)) {
            return null;
        }

        //获取所有的订单明细
        QueryMessageDTO detailQM = new QueryMessageDTO();
        detailQM.addCondition("orderUuid", QueryConditionEnum.IN.name(), list.stream().map(OrderMainPO::getUuid).collect(Collectors.toList()));
        List<OrderDetailPO> detailList = orderDetailService.queryByCondition(detailQM);

        if (CollectionUtils.isEmpty(detailList)) {
            return null;
        }

        //获取所有的商品图片
        QueryMessageDTO imgQM = new QueryMessageDTO();
        imgQM.addCondition("productUuid", QueryConditionEnum.IN.name(), detailList.stream().map(OrderDetailPO::getProductUuid).collect(Collectors.toList()));
        List<ProductImagePO> imgList = productImageService.queryByCondition(imgQM);
        //将图片集合转换成map, key=productUuid, value=ProductImagePO, 参数(key1, key2) -> key2 表示去重
        Map<String, ProductImagePO> imgMap = imgList.stream().collect(Collectors.toMap(ProductImagePO::getProductUuid, Function.identity(), (key1, key2) -> key2));

        for (OrderDetailPO detailPO : detailList) {
            ProductImagePO image = imgMap.get(detailPO.getProductUuid());
            if (null != image) {
                detailPO.setProductImg(image.getSmallImg());
            }
        }

        //订单明细根据orderUuid进行分组
        Map<String, List<OrderDetailPO>> detailMap = detailList.stream().collect(Collectors.groupingBy(OrderDetailPO::getOrderUuid));
        for (OrderMainPO order : list) {
            order.setDetailList(detailMap.get(order.getUuid()));
        }

        return list;
    }

    /**
     * 新订单通知推送
     * 异步调用
     *
     * @param orderUuid
     */
    @Override
    @Async("taskExecutor")
    public void pushOrderNotification(String orderUuid) {
        try {
            OrderMainPO po = this.getByUuid(orderUuid);

            /* 如果是线下支付的话，则要订单推送新订单通知消息 */
            if (po.getPayType() != PayTypeEnum.OFFLINE.getValue()) {
                return;
            }
            List<OrderDetailPO> detailPOList = orderDetailService.getDetailListByOrderUuid(orderUuid);
            OrderAddressPO orderAddressPO = orderAddressService.getAddressByOrderUuid(orderUuid);
            po.setDetailList(detailPOList);
            po.setOrderAddress(orderAddressPO);

            // 获取该商户的主账号
            String vendorUuid = po.getVendorUuid();
            List<VendorManagerPO> managers = vendorManagerService.getManagerByVendorUuidAndType(vendorUuid, EmployeeTypeEnum.BOSS.getValue());
            if (null != managers && managers.size() > 0) {
                String managerUuid = managers.get(0).getUuid();
                String title = "您有新的好吃佬订单，请及时处理!";
                Map<String, String> extras = new HashMap<>();
                extras.put("title", title);
                extras.put("opeType", "newOrder");
                extras.put("openUrl", orderDetailUrl + "?uuid=" + orderUuid);
                extras.put("data", JSON.toJSONString(po));
                extras.put("managerUuid", managerUuid);

                logger.info("下单极光推送数据：" + JSON.toJSONString(extras));

                /*
                 * 新启线程，新订单通知推送
                 * 调用极光推送推送新订单通知
                 */
               // jiguangPushClient.pushNotifacation(managerUuid, "", extras);
            }
        } catch (Exception e) {
            logger.error("下单推送失败，订单uuid=" + orderUuid, e);
        }

    }

    /**
     * 推送消息给后厨
     *
     * @param orderUuid
     */
    @Override
    @Async("taskExecutor")
    public void pushToChief(String orderUuid) {
        try {
            OrderMainPO po = this.getByUuid(orderUuid);
            List<OrderDetailPO> detailPOList = orderDetailService.getDetailListByOrderUuid(orderUuid);
            OrderAddressPO orderAddressPO = orderAddressService.getAddressByOrderUuid(orderUuid);
            po.setDetailList(detailPOList);
            po.setOrderAddress(orderAddressPO);

            String vendorUuid = po.getVendorUuid();
            List<VendorManagerPO> managers = vendorManagerService.getManagerByVendorUuidAndType(vendorUuid, EmployeeTypeEnum.HEADCHEF.getValue());
            if (null != managers && managers.size() > 0) {
                String managerUuid = managers.get(0).getUuid();
                String title = "您有新的好吃佬订单，请及时处理!";
                Map<String, String> extras = new HashMap<>();
                extras.put("title", title);
                extras.put("opeType", "printOrder");
                extras.put("openUrl", orderDetailUrl + "?uuid=" + orderUuid);
                extras.put("data", JSON.toJSONString(po));
                extras.put("managerUuid", managerUuid);

                logger.info("接单极光推送数据：" + JSON.toJSONString(extras));
                /*
                 * 新启线程，新订单通知推送给厨师长
                 */
               // jiguangPushClient.pushNotifacation(managerUuid, "", extras);
            }
        } catch (Exception e) {
            logger.error("接单推送失败，订单uuid=" + orderUuid, e);
        }

    }

    /**
     * 微信支付预下单
     *
     * @return
     */
    @Override
    public Map<String, Object> wxPreOrder(Map<String, Object> params) {
        String type = MapUtils.getString(params, "type");
        String wxplat = MapUtils.getString(params, "wxplat");
        String tradeType = MapUtils.getString(params, "tradeType");
        if ("SINGLEPAY".equals(type)) {
            String customerUuid = MapUtils.getString(params, "customerUuid");
            String vendorUuid = MapUtils.getString(params, "vendorUuid");
            CustomerPO customer = customerService.getByUuid(customerUuid);
            if (null == customer) {
                throw new InvalidParamException("会员不存在");
            }
            VendorPO vendor = vendorService.getByUuid(vendorUuid);
            if (null == vendor) {
                throw new InvalidParamException("商户不存在");
            }
            WeixinParamPO weixinParam = weixinParamService.getByVendorId(vendor.getUuid());
            WeixinPay weixinPay = new WeixinPay(weixinParam);
            String tradeNo = String.valueOf(new SnowflakeIdWorker().nextId());
            double payPrice = MapUtils.getDoubleValue(params, "payPrice");
            String createTime = DateFormatHelper.getNowTimeStr();
            String attach = MapUtils.getString(params, "couponUuid");
            return weixinPay.order(tradeNo, payPrice, createTime, attach, customer, vendor, wxplat, tradeType);
        } else {
            String orderUuid = MapUtils.getString(params, "orderUuid");
            OrderMainPO orderMain = orderMainRepository.getByUuid(orderUuid);
            if (null == orderMain) {
                throw new InvalidParamException("订单不存在");
            }
            CustomerPO customer = customerService.getByUuid(orderMain.getCustomerUuid());
            if (null == customer) {
                throw new InvalidParamException("会员不存在");
            }
            VendorPO vendor = vendorService.getByUuid(orderMain.getVendorUuid());
            if (null == vendor) {
                throw new InvalidParamException("商户不存在");
            }
            WeixinParamPO weixinParam = weixinParamService.getByVendorId(vendor.getUuid());
            WeixinPay weixinPay = new WeixinPay(weixinParam);
            return weixinPay.order(orderMain.getEntityNo(), orderMain.getPayPrice(), orderMain.getCreateTime(),
                    "", customer, vendor, wxplat, tradeType);
        }
    }

    /**
     * 微信退款申请
     *
     * @param orderUuid
     * @return
     */
    public Map<String, Object> wxReqRefund(String orderUuid, double refundFee, String refundReason) {
        OrderMainPO orderMain = orderMainRepository.getByUuid(orderUuid);
        if (null == orderMain) {
            throw new InvalidParamException("订单不存在");
        }
        CustomerPO customer = customerService.getByUuid(orderMain.getCustomerUuid());
        if (null == customer) {
            throw new InvalidParamException("会员不存在");
        }
        VendorPO vendor = vendorService.getByUuid(orderMain.getVendorUuid());
        if (null == vendor) {
            throw new InvalidParamException("商户不存在");
        }
        WeixinParamPO weixinParam = weixinParamService.getByVendorId(vendor.getUuid());
        WeixinPay weixinPay = new WeixinPay(weixinParam);
        return weixinPay.refund(orderMain, refundFee, refundReason);
    }

    /**
     * 订单加菜
     *
     * @param po
     */
    @Override
    public void addDish(OrderMainPO po) {
        OrderMainPO mainPO = this.getByUuid(po.getUuid());
        // 将新加的菜加到原来的明细中
        addDetails(mainPO, po);
        // 重新计算订单的相关数据
        genOrder(mainPO);
        // 重新计算订单的优惠数据
        genOrderDiscount(mainPO);

        // 重新更新订单主信息
        orderMainRepository.update(mainPO);
        // 删除原来的订单明细信息
        List<String> detailUuids = orderDetailService.getDetailUuidsByOrderUuid(po.getUuid());
        orderDetailService.deletes(detailUuids);
        // 更新订单明细信息
        orderDetailService.saveOrderDetail(mainPO);
        // 订单日志保存(加菜日志)
        orderLogService.createLog(mainPO.getUuid(), mainPO.getWaiterUuid(), "", "加菜");
    }

    /**
     * 将新添加的明细合并到原订单明细中
     *
     * @param mainPO
     * @param po
     */
    private void addDetails(OrderMainPO mainPO, OrderMainPO po) {
        List<OrderDetailPO> addDetails = po.getDetailList();
        List<OrderDetailPO> oldDetails = mainPO.getDetailList();
        List<String> oldProductUuids = oldDetails.stream().map(OrderDetailPO::getProductUuid).collect(Collectors.toList());
        Map<String, OrderDetailPO> map = oldDetails.stream().collect(Collectors.toMap(OrderDetailPO::getProductUuid, Function.identity()));
        for (OrderDetailPO newDetail : addDetails) {
            if (oldProductUuids.contains(newDetail.getProductUuid())) {
                OrderDetailPO detailPO = map.get(newDetail.getProductUuid());
                int buyNum = detailPO.getBuyNum();
                buyNum += buyNum + newDetail.getBuyNum();
                detailPO.setBuyNum(buyNum);
            } else {
                oldDetails.add(newDetail);
            }
        }
    }

    /**
     * 构造订单主要信息
     *
     * @param po
     */
    private void genOrder(OrderMainPO po) {
        double productTotalPrice = 0.0;
        List<OrderDetailPO> details = po.getDetailList();
        for (OrderDetailPO detail : details) {
            ProductMainPO mainPO = productMainRepository.getByUuid(detail.getProductUuid());
            detail.setProductName(mainPO.getName());
            //规格uuid为空
            if (StringUtils.isEmpty(detail.getSkuUuid())) {
                //不参与优惠
                if (0 == mainPO.getPromotionType()) {
                    detail.setProductPrice(mainPO.getPrice());
                } else {
                    detail.setProductPrice(DoubleFormatUtil.multiply(mainPO.getPrice(), mainPO.getPromotionRate()));
                }
            } else {
                //查询规格商品
                ProductAttrValuePO pav = productAttrValueService.getByUuid(detail.getSkuUuid());
                if (null == pav) {
                    //规格属性为空
                    throw new InvalidParamException(detail.getProductName() + " " + detail.getShowName() + ",已下架");
                }

                //不参与优惠
                if (0 == mainPO.getPromotionType()) {
                    detail.setProductPrice(pav.getPrice());
                } else {
                    double price = DoubleFormatUtil.multiply(pav.getPrice(), mainPO.getPromotionRate());
                    detail.setProductPrice(price);
                }
            }
            detail.setTotalPrice(DoubleFormatUtil.multiply(detail.getProductPrice(), detail.getBuyNum()));
            productTotalPrice = DoubleFormatUtil.add(productTotalPrice, detail.getTotalPrice());
        }
        //设置服务员uuids
        po.setWaiterUuids(po.getWaiterUuid());
        // 代客下单，无需配送费用
        po.setDeliveryPrice(0);
        // 设置菜品总金额
        po.setProductPrice(productTotalPrice);
        // 设置餐具费用
        VendorBasicPO vendorBasicPO = vendorBasicService.getByVendorUuid(po.getVendorUuid());
        po.setTablewarePrice(vendorBasicPO.getCoverPrice());
        // 设置订单总金额
        po.setTotalPrice(DoubleFormatUtil.add(productTotalPrice, po.getTablewarePrice()));
        // 设置就餐类型，为堂食
        po.setEatType(EatTypeEnum.TANGSHI.getValue());
        // 设置支付类型，线下支付
        po.setPayState(PayTypeEnum.OFFLINE.getValue());
        // 设置订单类型为实物订单
        po.setOrderType(OrderTypeEnum.ENTITY.getValue());
        // 设置订单状态
        po.setState(OrderStateEnum.SUBMIT.getValue());
        // 代客下单，不用赠送积分，因为没有用户信息
        po.setGiveIntegral(0);
        // 设置商户名称
        VendorPO vendorPO = vendorService.getByUuid(po.getVendorUuid());
        po.setVendorName(vendorPO.getVendorName());
    }

    /**
     * 构造订单优惠信息
     *
     * @param po
     */
    private void genOrderDiscount(OrderMainPO po) {
        // 查询商户的优惠设置
        // 代客下单，不用使用新用户立减的优惠，只使用满减
        VendorDiscountsPO vendorDiscountsPO = vendorDiscountsService.getByVendorUuid(po.getVendorUuid());
        // 设置满减金额
        if (vendorDiscountsPO.isMjOpen()) {
            if (po.getTotalPrice() >= vendorDiscountsPO.getMoney3()) {
                po.setMjPrice(vendorDiscountsPO.getFree3());
            } else if (po.getTotalPrice() >= vendorDiscountsPO.getMoney2()) {
                po.setMjPrice(vendorDiscountsPO.getFree2());
            } else if (po.getTotalPrice() >= vendorDiscountsPO.getMoney1()) {
                po.setMjPrice(vendorDiscountsPO.getFree1());
            }
        }
        // 设置优惠金额
        po.setFreePrice(po.getMjPrice() + po.getLjPrice() + po.getIntegralFree() + po.getOtherPrice());
        // 设置应付金额
        po.setPayPrice(po.getTotalPrice() - po.getFreePrice());
    }


    @Override
    public Map<String, Object> payNotify(Map<String, String> data) {
        Map<String, Object> result = new HashMap<>();
        String returnCode = MapUtils.getString(data, "return_code");
        String returnMessage = MapUtils.getString(data, "return_msg");
        if (!"SUCCESS".equalsIgnoreCase(returnCode)) {
            // 注意，这里返回SUCCESS是返回微信支付服务，告知已处理支付结果通知
            // 并不是表示业务成功
            // 如果不返回SUCCESS，微信支付服务会重复发送支付结果通知
            result.put("return_code", "SUCCESS");
            result.put("return_msg", returnMessage);
            return result;
        }
        WeixinParamPO weixinParam = weixinParamService.getByMchId(MapUtils.getString(data, "mch_id"));
        WeixinPay weixinPay = new WeixinPay(weixinParam);
        Map<String, Object> map = weixinPay.payNotify(data);
        if (MapUtils.getBooleanValue(map, "success")) {
            try {
                String couponUuid = MapUtils.getString(map, "attach");
                if (StringUtils.isNotBlank(couponUuid) && !"SINGLEPAY".equals(couponUuid)) {
                    // couponUuid 不为空，说明此支付是无订单支付，
                    // couponUuid 不为 SINGLEPAY 说明使用了优惠券 将优惠券标记为已使用即可
                    couponDetailService.used(couponUuid, null);
                } else {
                    this.pay(map);
                }
                savePayTransaction(map);
                result.put("return_code", "SUCCESS");
                result.put("return_msg", "支付完成");
            } catch (InvalidParamException e) {
                logger.error("【微信支付】{}", e.getMessage());
                result.put("return_code", "FAIL");
                result.put("return_msg", e.getMessage());
            } catch (Exception e) {
                logger.error("【微信支付】处理支付结果失败", e);
                result.put("return_code", "FAIL");
                result.put("return_msg", "处理支付结果失败");
            }
        } else if (!MapUtils.getBooleanValue(map, "success") && "SUCCESS".equals(MapUtils.getString(map, "return_code"))) {
            OrderMainPO order = this.getByOrderId(MapUtils.getString(data, "out_trade_no"));
            if (null != order) {
                // 保存支付失败原因
                order.setNote(MapUtils.getString(map, "return_msg"));
                orderMainRepository.update(order);
            }
            // 支付失败
            result.put("return_code", MapUtils.getString(map, "return_code"));
            result.put("return_msg", MapUtils.getString(map, "return_msg"));
        } else {
            // 处理支付结果失败
            result.put("return_code", MapUtils.getString(map, "return_code"));
            result.put("return_msg", MapUtils.getString(map, "return_msg"));
        }
        return result;
    }

    private void savePayTransaction(Map<String, Object> result) {
        TransactionPO transaction = new TransactionPO();
        transaction.setUuid(BasicPO.genUuid());
        transaction.setSerialNo(new SnowflakeIdWorker().nextId());
        transaction.setOrderNo(MapUtils.getString(result, "orderNo"));
        transaction.setPayType(PayTypeEnum.WECHATPAY.getValue());
        transaction.setPayScene(MapUtils.getInteger(result, "wechatPay"));
        transaction.setAppid(MapUtils.getString(result, "appid"));
        transaction.setMchid(MapUtils.getString(result, "mchId"));
        transaction.setPayId(MapUtils.getString(result, "transactionId"));
        transaction.setDeviceInfo(MapUtils.getString(result, "deviceInfo"));
        transaction.setPayerInfo(MapUtils.getString(result, "openid"));
        transaction.setPayAmount(MapUtils.getDouble(result, "totalFee"));
        transaction.setPayTime(MapUtils.getString(result, "payTime"));
        transaction.setBankType(MapUtils.getString(result, "bankType"));
        transactionService.create(transaction);
    }

    @Override
    public Map<String, Object> refundNotify(Map<String, String> data) {
        Map<String, Object> result = new HashMap<>();
        String returnCode = MapUtils.getString(data, "return_code");
        String returnMessage = MapUtils.getString(data, "return_msg");
        if (!"SUCCESS".equalsIgnoreCase(returnCode)) {
            // 注意，这里返回SUCCESS是返回微信支付服务，告知已处理支付结果通知
            // 并不是表示业务成功
            // 如果不返回SUCCESS，微信支付服务会重复发送支付结果通知
            result.put("return_code", "SUCCESS");
            result.put("return_msg", returnMessage);
            return result;
        }
        WeixinParamPO weixinParam = weixinParamService.getByMchId(MapUtils.getString(data, "mch_id"));
        WeixinPay weixinPay = new WeixinPay(weixinParam);
        Map<String, Object> map = weixinPay.refundNotify(data);
        if (MapUtils.getBooleanValue(map, "success")) {
            try {
                String orderNo = MapUtils.getString(map, "out_trade_no");
                String refundStatus = MapUtils.getString(map, "refund_status");
                String successTime = MapUtils.getString(map, "success_time");
                String callbakcMsg = MapUtils.getString(map, "refund_status");
                refundCallback(orderNo, refundStatus, successTime, callbakcMsg);
                updateTransactionForRefund(map);
                result.put("return_code", "SUCCESS");
                result.put("return_msg", "退款完成");
            } catch (InvalidParamException e) {
                logger.error("【微信支付】{}", e.getMessage());
                result.put("return_code", "FAIL");
                result.put("return_msg", e.getMessage());
            } catch (Exception e) {
                logger.error("【微信支付】处理退款结果失败", e);
                result.put("return_code", "FAIL");
                result.put("return_msg", "处理退款结果失败");
            }
        } else {
            // 处理支付结果失败
            result.put("return_code", MapUtils.getString(map, "return_code"));
            result.put("return_msg", MapUtils.getString(map, "return_msg"));
        }
        return result;
    }

    private void updateTransactionForRefund(Map<String, Object> result) {
        TransactionPO transaction = transactionService.getByPayId(MapUtils.getString(result, "transaction_id"));
        if (null == transaction) {
            transaction = new TransactionPO();
            transaction.setUuid(BasicPO.genUuid());
            transaction.setSerialNo(new SnowflakeIdWorker().nextId());
            transaction.setOrderNo(MapUtils.getString(result, "out_trade_no"));
            transaction.setPayType(PayTypeEnum.WECHATPAY.getValue());
            transaction.setPayId(MapUtils.getString(result, "transaction_id"));
            transaction.setAppid(MapUtils.getString(result, "appid"));
            transaction.setMchid(MapUtils.getString(result, "mch_id"));
        }
        transaction.setRefundId(MapUtils.getString(result, "refund_id"));
        transaction.setRefundNo(MapUtils.getString(result, "out_refund_no"));
        transaction.setRefundAmount(MapUtils.getDouble(result, "settlement_refund_fee"));
        transaction.setRefundTime(MapUtils.getString(result, "success_time"));
        transaction.setRefundTo(MapUtils.getString(result, "refund_recv_accout"));

        transactionService.createOrUpdate(transaction);
    }
}
